サーバレス関数合成とオーケストレーションが、フロントエンドアーキテクチャをどのように変革し、クライアント側のロジックを簡素化し、耐障害性とスケーラブルなアプリケーションを構築できるかを探ります。
フロントエンドサーバレスアーキテクチャ:関数合成とオーケストレーションの詳細
進化し続けるウェブ開発の状況において、フロントエンドの役割は、単純なユーザーインターフェースのレンダリングから、複雑なアプリケーション状態の管理、複雑なビジネスロジックの処理、および多数の非同期操作のオーケストレーションへと移行しました。アプリケーションの洗練度が増すにつれて、舞台裏の複雑さも増します。従来のモノリシックバックエンド、さらには第一世代のマイクロサービスアーキテクチャでさえ、ボトルネックが発生し、フロントエンドのアジリティがバックエンドのリリースサイクルに結び付けられることがあります。そこで、フロントエンド専用のサーバレスアーキテクチャがパラダイムシフトをもたらします。
しかし、サーバレスの採用は、単に個々の関数を作成するほど簡単ではありません。最新のアプリケーションが、単一の孤立したアクションでタスクを実行することはめったにありません。多くの場合、一連のステップ、並列プロセス、および条件付きロジックが含まれます。モノリシックな考え方に戻ったり、相互接続された関数が絡み合った混乱を作り出したりすることなく、これらの複雑なワークフローをどのように管理すればよいでしょうか。その答えは、関数合成と関数オーケストレーションという2つの強力な概念にあります。
この包括的なガイドでは、これらのパターンがBackend-for-Frontend(BFF)レイヤーをどのように変革し、開発者が堅牢でスケーラブル、かつ保守可能なアプリケーションを構築できるようにするかを探ります。コアコンセプトを分析し、一般的なパターンを検証し、主要なクラウドオーケストレーションサービスを評価し、理解を深めるための実践的な例を説明します。
フロントエンドアーキテクチャの進化とサーバレスBFFの台頭
サーバレスオーケストレーションの重要性を理解するには、フロントエンドアーキテクチャの歩みを理解することが役立ちます。サーバーでレンダリングされたページから、RESTまたはGraphQL APIを介してバックエンドと通信するリッチなシングルページアプリケーション(SPA)へと移行しました。この関心の分離は大きな飛躍でしたが、新たな課題が生まれました。
モノリスからマイクロサービス、そしてBFFへ
当初、SPAは多くの場合、単一のモノリシックなバックエンドAPIと通信していました。これは単純でしたが、脆いものでした。モバイルアプリに対する小さな変更が、ウェブアプリを破壊する可能性がありました。マイクロサービス運動は、モノリスをより小さく、独立してデプロイ可能なサービスに分割することで、これに対処しました。ただし、これにより、フロントエンドが単一のビューをレンダリングするために複数のマイクロサービスを呼び出す必要が生じることが多く、おしゃべりで複雑なクライアント側のロジックにつながりました。
Backend-for-Frontend(BFF)パターンが解決策として登場しました。BFFは、特定のフロントエンドエクスペリエンス(ウェブアプリ用、iOSアプリ用など)専用のバックエンドレイヤーです。これはファサードとして機能し、さまざまなダウンストリームマイクロサービスからデータを集約し、API応答をクライアントのニーズに合わせて調整します。これにより、フロントエンドコードが簡素化され、ネットワークリクエストの数が減り、パフォーマンスが向上します。
BFFに最適なサーバレス
サーバレス関数、またはFunction-as-a-Service(FaaS)は、BFFを実装するのに自然に適しています。BFFのために常に実行されているサーバーを維持する代わりに、小さく、イベント駆動型の関数のコレクションをデプロイできます。各関数は、ユーザーデータのフェッチ、支払いの処理、ニュースフィードの集約など、特定のAPIエンドポイントまたはタスクを処理できます。
このアプローチには、信じられないほどのメリットがあります。
- スケーラビリティ:関数は、需要に基づいて自動的にゼロから数千の呼び出しにスケーリングされます。
- 費用対効果:使用したコンピューティング時間に対してのみ料金を支払うため、BFFの多くの場合バースト状のトラフィックパターンに最適です。
- 開発者のベロシティ:小さく、独立した関数は、開発、テスト、およびデプロイが容易です。
ただし、これにより新たな課題が生じます。アプリケーションの複雑さが増すにつれて、BFFは、1つのクライアントリクエストを満たすために、特定の順序で複数の関数を呼び出す必要がある場合があります。たとえば、ユーザーのサインアップには、データベースレコードの作成、課金サービスの呼び出し、およびウェルカムメールの送信が含まれる場合があります。フロントエンドクライアントにこのシーケンスを管理させることは、非効率的で安全ではありません。これは、関数合成とオーケストレーションが解決するように設計されている問題です。
コアコンセプトの理解:合成とオーケストレーション
パターンとツールに入る前に、主要な用語の明確な定義を確立しましょう。
サーバレス関数(FaaS)とは何ですか?
コアにおいて、サーバレス関数(AWS Lambda、Azure Functions、またはGoogle Cloud Functionsなど)は、イベントに応じて実行されるステートレスで短命なコンピューティングインスタンスです。イベントは、API GatewayからのHTTPリクエスト、ストレージバケットへの新しいファイルアップロード、またはキュー内のメッセージである可能性があります。重要な原則は、開発者であるあなたが、基盤となるサーバーを管理しないことです。
関数合成とは何ですか?
関数合成は、複数の単純な単一目的の関数を組み合わせることによって複雑なプロセスを構築する設計パターンです。レゴブロックで構築するようなものと考えてください。各ブロック(関数)には、特定の形状と目的があります。さまざまな方法で接続することにより、精巧な構造(ワークフロー)を構築できます。合成の焦点は、関数間のデータの流れにあります。
関数オーケストレーションとは何ですか?
関数オーケストレーションは、その合成の実装と管理です。これには、事前定義されたワークフローに従って関数の実行を指示する中央コントローラー(オーケストレーター)が含まれます。オーケストレーターは、次の役割を担います。
- フロー制御:関数を順番に、並行して、または条件付きロジック(分岐)に基づいて実行します。
- 状態管理:ワークフローの進行状況を追跡し、ステップ間でデータを渡します。
- エラー処理:関数からのエラーをキャッチし、再試行ロジックまたは補償アクション(トランザクションのロールバックなど)を実装します。
- 調整:複数ステップのプロセス全体が単一のトランザクションユニットとして正常に完了することを保証します。
合成 vs. オーケストレーション:明確な区別
違いを理解することが重要です。
- 合成は設計または「何を」です。eコマースのチェックアウトの場合、合成は次のようになります:1.カートの検証 -> 2.支払いの処理 -> 3.注文の作成 -> 4.確認の送信。
- オーケストレーションは実行エンジンまたは「どのように」です。オーケストレーターは、実際に`validateCart`関数を呼び出し、その応答を待ち、次に結果を使用して`processPayment`関数を呼び出し、再試行で支払いの失敗を処理するなどを行うサービスです。
単純な合成は、1つの関数が別の関数を直接呼び出すことで実現できますが、これにより結合度が強くなり、脆弱になります。真のオーケストレーションは、関数をワークフローロジックから分離し、より回復力があり、保守可能なシステムにつながります。
サーバレス関数合成のパターン
サーバレス関数を合成するときに、いくつかの一般的なパターンが現れます。これらを理解することは、効果的なワークフローを設計するための鍵となります。
1. チェーン(順次実行)
これは最も単純なパターンであり、関数はシーケンスで次々に実行されます。最初の関数の出力が2番目の関数の入力になり、以下同様です。これは、パイプラインのサーバレス同等物です。
ユースケース:画像処理ワークフロー。フロントエンドが画像をアップロードし、ワークフローをトリガーします。
- 関数A(ValidateImage):ファイルの種類とサイズを確認します。
- 関数B(ResizeImage):いくつかのサムネイルバージョンを作成します。
- 関数C(AddWatermark):サイズ変更された画像に透かしを追加します。
- 関数D(SaveToBucket):最終画像をクラウドストレージバケットに保存します。
2. ファンアウト/ファンイン(並列実行)
このパターンは、パフォーマンスを向上させるために、複数の独立したタスクを同時に実行できる場合に使用されます。単一の関数(ファンアウト)が、他の複数の関数をトリガーして並行して実行します。最後の関数(ファンイン)は、すべての並列タスクが完了するのを待ってから、結果を集約します。
ユースケース:ビデオファイルの処理。ビデオがアップロードされ、ワークフローがトリガーされます。
- 関数A(StartProcessing):ビデオファイルを受信し、並列タスクをトリガーします。
- 並列タスク:
- 関数B(TranscodeTo1080p):1080pバージョンを作成します。
- 関数C(TranscodeTo720p):720pバージョンを作成します。
- 関数D(ExtractAudio):オーディオトラックを抽出します。
- 関数E(GenerateThumbnails):プレビューサムネイルを生成します。
- 関数F(AggregateResults):B、C、D、Eが完了すると、この関数は生成されたすべてのアセットへのリンクでデータベースを更新します。
3. 非同期メッセージング(イベント駆動型コレオグラフィー)
厳密にはオーケストレーションではありませんが(コレオグラフィーと呼ばれることが多い)、このパターンはサーバレスアーキテクチャでは不可欠です。中央コントローラーの代わりに、関数はメッセージバスまたはキュー(AWS SNS/SQS、Google Pub/Sub、Azure Service Busなど)にイベントを発行することによって通信します。他の関数はこれらのイベントをサブスクライブし、それに応じて反応します。
ユースケース:注文配置システム。
- フロントエンドが`placeOrder`関数を呼び出します。
- `placeOrder`関数は、注文を検証し、`OrderPlaced`イベントをメッセージバスに発行します。
- 複数の独立したサブスクライバー関数がこのイベントに応答します。
- `billing`関数は、支払いを処理します。
- `shipping`関数は、倉庫に通知します。
- `notifications`関数は、顧客に確認メールを送信します。
マネージドオーケストレーションサービスの力
これらのパターンを手動で実装することもできますが、状態の管理、エラーの処理、および実行の追跡はすぐに複雑になります。ここで、主要なクラウドプロバイダーからのマネージドオーケストレーションサービスが非常に貴重になります。これらは、複雑なワークフローを定義、視覚化、および実行するためのフレームワークを提供します。
AWS Step Functions
AWS Step Functionsは、ワークフローをステートマシンとして定義できるサーバレスオーケストレーションサービスです。Amazon States Language(ASL)と呼ばれるJSONベースの形式を使用して、ワークフローを宣言的に定義します。
- コアコンセプト:視覚的に設計可能なステートマシン。
- 定義:宣言型JSON(ASL)。
- 主な機能:視覚的なワークフローエディタ、組み込みの再試行およびエラー処理ロジック、ヒューマンインザループワークフロー(コールバック)のサポート、および200を超えるAWSサービスとの直接統合。
- 最適な用途:視覚的で宣言的なアプローチとAWSエコシステムとの緊密な統合を好むチーム。
単純なシーケンスのASLスニペットの例:
{
"Comment": "単純な順次ワークフロー",
"StartAt": "FirstState",
"States": {
"FirstState": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:MyFirstFunction",
"Next": "SecondState"
},
"SecondState": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:MySecondFunction",
"End": true
}
}
}
Azure Durable Functions
Durable Functionsは、Azure Functionsの拡張機能であり、コードファーストのアプローチでステートフルワークフローを作成できます。宣言型言語の代わりに、C#、Python、またはJavaScriptなどの汎用プログラミング言語を使用してオーケストレーションロジックを定義します。
- コアコンセプト:コードとしてオーケストレーションロジックを作成します。
- 定義:命令型コード(C#、Python、JavaScriptなど)。
- 主な機能:イベントソーシングパターンを使用して、状態を確実に維持します。オーケストレーター、アクティビティ、およびエンティティ関数などの概念を提供します。状態はフレームワークによって暗黙的に管理されます。
- 最適な用途:JSONまたはYAMLではなく、使い慣れたプログラミング言語内で複雑なロジック、ループ、および分岐を定義することを好む開発者。
単純なシーケンスのPythonスニペットの例:
import azure.durable_functions as df
def orchestrator_function(context: df.DurableOrchestrationContext):
result1 = yield context.call_activity('MyFirstFunction', 'input1')
result2 = yield context.call_activity('MySecondFunction', result1)
return result2
Google Cloud Workflows
Google Cloud Workflowsは、YAMLまたはJSONを使用してワークフローを定義できるフルマネージドオーケストレーションサービスです。Google CloudサービスとHTTPベースのAPIの接続と自動化に優れています。
- コアコンセプト:YAML/JSONベースのワークフロー定義。
- 定義:宣言型YAMLまたはJSON。
- 主な機能:外部サービスを呼び出すための強力なHTTPリクエスト機能、Google Cloudサービスの組み込みコネクタ、モジュール設計のサブワークフロー、および堅牢なエラー処理。
- 最適な用途:Google Cloudエコシステムの内外を問わず、HTTPベースのAPIのチェーンを多用するワークフロー。
単純なシーケンスのYAMLスニペットの例:
main:
params: [args]
steps:
- first_step:
call: http.post
args:
url: https://example.com/myFirstFunction
body:
input: ${args.input}
result: firstResult
- second_step:
call: http.post
args:
url: https://example.com/mySecondFunction
body:
data: ${firstResult.body}
result: finalResult
- return_value:
return: ${finalResult.body}
実践的なフロントエンドシナリオ:ユーザーオンボーディングワークフロー
一般的な現実世界の例である、アプリケーションにサインアップする新しいユーザーを使用して、すべてを結び付けましょう。必要な手順は次のとおりです。
- プライマリデータベースにユーザーレコードを作成します。
- 並行して:
- ウェルカムメールを送信します。
- ユーザーのIPとメールに基づいて不正チェックを実行します。
- 不正チェックに合格した場合、課金システムでトライアルサブスクリプションを作成します。
- 不正チェックに失敗した場合、アカウントにフラグを立ててサポートチームに通知します。
- 成功または失敗のメッセージをユーザーに返します。
解決策1:「ナイーブ」なフロントエンド駆動型アプローチ
オーケストレーションされたBFFがない場合、フロントエンドクライアントはこのロジックを管理する必要があります。API呼び出しのシーケンスを作成します。
- `POST /api/users` -> 応答を待ちます。
- `POST /api/emails/welcome` -> バックグラウンドで実行されます。
- `POST /api/fraud-check` -> 応答を待ちます。
- 不正チェックの応答に基づくクライアント側の`if/else`:
- 合格した場合:`POST /api/subscriptions/trial`。
- 失敗した場合:`POST /api/users/flag`。
このアプローチは非常に欠陥があります:
- 脆くておしゃべり:クライアントはバックエンドプロセスに緊密に結合されています。ワークフローを変更するには、フロントエンドのデプロイが必要です。また、複数のネットワークリクエストが行われます。
- トランザクションの整合性がない:ユーザーレコードが作成された後、サブスクリプションの作成に失敗した場合はどうなりますか?システムは整合性のない状態になり、クライアントは複雑なロールバックロジックを処理する必要があります。
- 貧弱なユーザーエクスペリエンス:ユーザーは、複数のシーケンシャルネットワーク呼び出しが完了するのを待つ必要があります。
- セキュリティリスク:`flag-user`や`create-trial`のような詳細なAPIをクライアントに直接公開すると、セキュリティの脆弱性になる可能性があります。
解決策2:オーケストレーションされたサーバレスBFFアプローチ
オーケストレーションサービスを使用すると、アーキテクチャが大幅に改善されます。フロントエンドは、1つの安全なAPI呼び出しのみを行います。
POST /api/onboarding
このAPI Gatewayエンドポイントは、ステートマシン(AWS Step Functionsなど)をトリガーします。オーケストレーターが引き継ぎ、ワークフローを実行します。
- 開始状態:API呼び出しからユーザーデータを受信します。
- ユーザーレコードの作成(タスク):Lambda関数を呼び出して、DynamoDBまたはリレーショナルデータベースにユーザーを作成します。
- 並列状態:2つのブランチを同時に実行します。
- ブランチ1(メール):Lambda関数またはSNSトピックを呼び出して、ウェルカムメールを送信します。
- ブランチ2(不正チェック):サードパーティの不正検出サービスを呼び出すLambda関数を呼び出します。
- 選択状態(分岐ロジック):不正チェックステップの出力を検査します。
- `fraud_score < threshold`(合格)の場合:「サブスクリプションの作成」状態に移行します。
- `fraud_score >= threshold`(不合格)の場合:「アカウントのフラグ」状態に移行します。
- サブスクリプションの作成(タスク):Lambda関数を呼び出して、StripeまたはBraintree APIとやり取りします。成功すると、「成功」終了状態に移行します。
- アカウントのフラグ(タスク):Lambdaを呼び出してユーザーレコードを更新し、別のLambdaまたはSNSトピックを呼び出してサポートチームに通知します。「失敗」終了状態に移行します。
- 終了状態(成功/失敗):ワークフローが終了し、API Gatewayを介してクリーンな成功または失敗メッセージをフロントエンドに返します。
このオーケストレーションされたアプローチのメリットは非常に大きいです:
- 簡素化されたフロントエンド:クライアントの唯一のジョブは、1つの呼び出しを行い、1つの応答を処理することです。すべての複雑なロジックはバックエンドにカプセル化されています。
- 回復力と信頼性:オーケストレーターは、失敗したステップを自動的に再試行できます(課金APIが一時的に利用できない場合など)。プロセス全体がトランザクションです。
- 可視性とデバッグ:マネージドオーケストレーターは、すべての実行の詳細なビジュアルログを提供するため、ワークフローが失敗した場所とその理由を簡単に確認できます。
- 保守性:ワークフローロジックは、関数内のビジネスロジックから分離されています。個々のLambda関数に触れることなく、ワークフローを変更(新しいステップの追加など)できます。
- 強化されたセキュリティ:フロントエンドは、1つの強化されたAPIエンドポイントのみとやり取りします。詳細な関数とその権限は、バックエンドVPCまたはネットワーク内に隠されています。
フロントエンドサーバレスオーケストレーションのベストプラクティス
これらのパターンを採用する際に、アーキテクチャをクリーンで効率的な状態に保つために、これらのグローバルなベストプラクティスを念頭に置いてください。
- 関数を粒度が高くステートレスに保つ:各関数は1つのことをうまく行う必要があります(単一責任原則)。関数が独自の状態を維持することは避けてください。これはオーケストレーターの仕事です。
- オーケストレーターに状態を管理させる:大きな複雑なJSONペイロードをある関数から別の関数に渡さないでください。代わりに、最小限のデータ(`userID`や`orderID`など)を渡し、各関数が必要なデータをフェッチできるようにします。オーケストレーターは、ワークフローの状態の信頼できる情報源です。
- 冪等性のために設計する:関数が意図しない副作用を引き起こすことなく安全に再試行できることを確認します。たとえば、`createUser`関数は、新しいユーザーを作成しようとする前に、そのメールアドレスを持つユーザーがすでに存在するかどうかを確認する必要があります。これにより、オーケストレーターがステップを再試行した場合に、重複レコードが防止されます。
- 包括的なロギングとトレースを実装する:AWS X-Ray、Azure Application Insights、またはGoogle Cloud Traceのようなツールを使用して、API Gateway、オーケストレーター、および複数の関数を通過するリクエストの統合ビューを取得します。すべての関数呼び出しでオーケストレーターからの実行IDをログに記録します。
- ワークフローを保護する:最小権限の原則を使用します。オーケストレーターのIAMロールは、ワークフロー内の特定の関数を呼び出す権限のみを持つ必要があります。次に、各関数は、タスクを実行するために必要な権限(特定のデータベーステーブルに対する読み取り/書き込みなど)のみを持つ必要があります。
- いつオーケストレーションするかを知る:オーバーエンジニアリングしないでください。単純なA -> Bチェーンの場合、直接呼び出しで十分な場合があります。ただし、分岐、並列タスク、または堅牢なエラー処理と再試行の必要性が生じた場合は、専用のオーケストレーションサービスを使用すると、時間を大幅に節約し、将来の頭痛の種を防ぐことができます。
結論:次世代のフロントエンドエクスペリエンスの構築
関数合成とオーケストレーションは、バックエンドインフラストラクチャの問題だけではありません。これらは、洗練された信頼性の高いスケーラブルな最新のフロントエンドアプリケーションを構築するための基本的なイネーブラーです。複雑なワークフローロジックをクライアントからオーケストレーションされたサーバレスBackend-for-Frontendに移動することにより、フロントエンドチームが最も得意とすること(優れたユーザーエクスペリエンスの作成)に集中できるようにします。
このアーキテクチャパターンは、クライアントを簡素化し、ビジネスプロセスロジックを一元化し、システム回復力を向上させ、アプリケーションの最も重要なワークフローに対する比類のない可視性を提供します。AWS Step FunctionsとGoogle Cloud Workflowsの宣言的なパワー、またはAzure Durable Functionsのコードファーストの柔軟性のどちらを選択する場合でも、オーケストレーションを採用することは、フロントエンドアーキテクチャの長期的な健全性と俊敏性への戦略的投資です。
サーバレス時代が到来し、それは単なる関数以上のものです。強力なイベント駆動型システムを構築することです。合成とオーケストレーションを習得することで、このパラダイムの可能性を最大限に引き出し、回復力があり、グローバルにスケーラブルな次世代アプリケーションへの道を開きます。